#include "tp2.h"

int main() {
  char opt;
  char alvo[MAX_TITULO];
  Registro reg;
  int state = 0;
  Obra novo;
  FILE *fpt;
  printf("***Bem vindo ao acervo 05***\n");
  ImprimeMenu();
  reg = LoadChaves(reg);
  while(state == 0){ 
    scanf("%c", &opt);
    getchar();
    switch(opt) {  
    case '1':
      fpt = fopen("base05.dat", "a+");
      ScaneiaObra(&novo, reg);
      reg = JogaRam(reg, &novo);	
      FilePrint(&novo, &fpt);
      fclose(fpt);
      ImprimeMenu();
      break;
    case '2':
      printf("Entre com o Titulo da obra a ser procurada:\n");
      /*funcao da biblioteca padrao que ordena o vetor de registros em ordem alfabetica*/
      qsort(reg.vetor, reg.quantidade, sizeof(Chave_prim), nosso_strcmp);
      strcpy(alvo,  CompletaString(alvo, MAX_TITULO));
      strcpy(alvo, Scaneia(alvo, MAX_TITULO));
      Busca(reg, 0, alvo);
      printf("\n");
      ImprimeMenu();	
      break;	
    case '3':
      qsort(reg.vetor, reg.quantidade, sizeof(Chave_prim), nosso_strcmp);
      Lista(reg);
      printf("\n");
      ImprimeMenu();
      break; 
    case '4':
      state = 1;
      break;
    case 'h':
      printf("Entre com '1' para adicionar obras ao acervo.\n");
      printf("Entre com '2' para procurar uma obra.\n");
      printf("Entre com '3' para listar as obras.\n");
      printf("Entre com '4' para sair do programa.\n");
      break;
    default:
      printf("Opção inválida. Aperte 'h' para ajuda.\n");
      break;    
    }
    
  }
  qsort(reg.vetor, reg.quantidade, sizeof(Chave_prim), nosso_strcmp);
  GravaChaves(reg);	
  return 0;
}

/*funcao usada para imprimir na tela as opções do usuario*/ 
void ImprimeMenu(){
  
  printf("Entre com '1' para adicionar outras obras ao acervo.\n");
  printf("Entre com '2' para procurar uma obra.\n");
  printf("Entre com '3' para listar as obras.\n");
  printf("Entre com '4' para sair do programa.\n");
  printf("Entre com uma opção ou entre com 'h' para ajuda.\n"); 
  
  return;
}


/*funcao VerificaNum:
  Verifica se o char passado como parametro é ou nao um número
  e retorna este número, ou retorna 10 caso não seja um número
*/
int VerificaNum(char i){
  if(i >= '0' && i <= '9') return i - '0';
  return 10;
}

/*Função Scaneia:
  escaneia uma string, recebendo como parametro o campo a ser scaneado e seu tamanho
  ao final da funcao , retorna a string scaneada*/
char *Scaneia(char *campo, int tamanho){
  int cont;
  char a;
  cont = 0;
  scanf("%c", &campo[cont]);
  while(campo[cont] != '\n'){	
    if (cont > tamanho - 2) {
      /*caso a string esteja completa, joga o excesso de caracteres na variável "a"*/ 
      while (a != '\n') { 				
	scanf("%c", &a);
      }
      break;
    }
    cont++; 
    scanf("%c", &campo[cont]);
  }
  /*substitui o '\n' guardado no vetor por um espaço
   */
  if (cont <= tamanho - 2) campo[cont] = ' ';
  /*Atribui '\0' no final do vetor para garantir que foi demarcado o fim do vetor*/ 
  campo[tamanho-1] = '\0';
  
  
  return campo;
}

/*função ScaneiaObra:
  Escaneia os campos de string de uma nova Obra usando a função Scaneia.Em seguida, escaneia os campos Ano e Valor verificando se os caracteres digitados são numeros.Por ultimo, escaneia o campo Imagem por meio da função Scaneia.
  Ela utiliza a função busca para verificar se um titulo a ser inserido já existe no banco.
*/  
void ScaneiaObra(Obra *novo, Registro reg){	
  int aux[MAX_VALOR];
  int cont = 0, ind_aux, tamanho;
  int confirma_busca;
  char alvo[MAX_TITULO];
  char a;
  printf("Entre com o Titulo da obra:\n");
  tamanho = MAX_TITULO;
  strcpy(alvo,  CompletaString(alvo, tamanho));
  strcpy(alvo, Scaneia(alvo, tamanho));
  if(reg.quantidade != 0){
    confirma_busca = Busca(reg, 1, alvo);
    while(confirma_busca == 1){
      printf("Obra ja existente. Digite novo Titulo de obra:\n");
      strcpy(alvo,  CompletaString(alvo, tamanho));
      strcpy(alvo, Scaneia(alvo, tamanho));
      confirma_busca = Busca(reg, 1, alvo);
    }
  }
  strcpy(novo->Titulo, alvo);
  strcpy(novo->Titulo, alvo);
  
  printf("Entre com o Tipo da obra:\n");
  tamanho = MAX_TIPO;
  strcpy(novo->Tipo, CompletaString(novo->Tipo, tamanho));
  strcpy(novo->Tipo, Scaneia(novo->Tipo, tamanho));
  
  printf("Entre com o Autor da Obra:\n");
  tamanho = MAX_AUTOR;
  strcpy(novo->Autor, CompletaString(novo->Autor, tamanho));
  strcpy(novo->Autor, Scaneia(novo->Autor, tamanho));
  
  printf("Entre com o Ano da Obra. Caracteres serao desconsiderados:\n");
  scanf("%c", &a);
  while(a != '\n'){
    /*Utiliza VerificaNum para retornar ou o inteiro equivalente,
      passando seu valor para um vetor auxiliar,  ou 10
      caso seja um caractere 		
    */
    ind_aux = VerificaNum(a);
    if (ind_aux < 10) {
      aux[cont] = ind_aux;
      cont++;
      /*Caso o usuario jah tenha entrado com 4 numeros, joga o resto fora
       */
      if (cont  == MAX_ANO){
        while(a != '\n'){
          scanf("%c", &a);
        }         
        break;
      }
    }                     
    scanf("%c", &a);        
  }
  /*zera o vetor da struct, para que ele possa receber o espaço ano
   */
  ind_aux = 0;
  while(ind_aux < MAX_ANO){
    novo->Ano[ind_aux] = 0;
    ind_aux++;
  }
  /*o vetor auxiliar, que contem o ano, é repassado para a struct,
    sendo todos os números jogados para o final do vetor,
    para que o ano, caso tenha menos que 3 digitos, seja completado
    por "0" a esquerda
  */     
  while(cont > 0){
    novo->Ano[ind_aux-1] = aux[cont-1];
    cont--;
    ind_aux--;
  } 
  a = 'a';     
  cont = 0;
  
  printf("Entre com o Valor da Obra. Caracteres serao desconsiderados:\n");
  scanf("%c", &a);
  /*processo identico ao usado para o campo "Ano"
   */
  while(a != '\n'){
    ind_aux = VerificaNum(a);
    if (ind_aux < 10) {
      aux[cont] = ind_aux;
      cont++;
      /*jogando lixo fora
       */
      if (cont  == MAX_VALOR){
        while(a != '\n'){
          scanf("%c", &a);
        }         
        break;
      }
    }                     
    scanf("%c", &a);        
  }
  
  ind_aux = 0;
  while(ind_aux < MAX_VALOR){
    novo->Valor[ind_aux] = 0;
    ind_aux++;
  }
  /*repassando o valor para o vetor struct em processo identico ao do campo Ano
   */     
  while(cont > 0){
    novo->Valor[ind_aux-1] = aux[cont-1];
    cont--;
    ind_aux--;
  }
  /*scan de campo imagem:
    espera-se a entrada padrão, que deve conter 4 numeros e 3 caracteres, 
    não sendo, portanto, verificada a entrada do usuario*/ 
  printf("Entre com a Imagem da Obra:\n");	
  strcpy(novo->Imagem, Scaneia(novo->Imagem, MAX_IMAGEM));
  return;
}

/*Função JogaRam:
  Passa a chave primária e o nrr dos registros inseridos durante a execução para a memória. Caso não exista nenhum registro na mémoria, aloca o vetor de registros na memória em sua 1a chamada e aloca mais 20 espaços sempre que necessário. Ao fim da execução, retorna o registro "reg" atualizado.*/
Registro JogaRam(Registro reg, Obra *novo){
  int k;
  k = (int)reg.quantidade/20 + 1;
  if(reg.quantidade%20 == 0){	
    reg.vetor = (Chave_prim *)realloc(reg.vetor, (k)*20*(sizeof(Chave_prim)));
  }
  strcpy(reg.vetor[reg.quantidade].Titulo, novo->Titulo);
  reg.vetor[reg.quantidade].nrr = reg.quantidade;
  reg.quantidade++;
  return reg;
}	
/*Função FilePrint:
  registra todos os dados contidos na struct em um arquivo
*/
void FilePrint(Obra *novo, FILE **fpt){
  int cont = 0;
  /*registra no arquivo os campos Titulo, Tipo e Autor, 
   */
  fprintf(*fpt, "%s", novo->Titulo);		
  fprintf(*fpt, "%s", novo->Tipo);
  fprintf(*fpt, "%s", novo->Autor);
  /*registra os campos Ano e Valor através de um laço, inteiro por inteiro, 
    já que não se pode usar "%s" por não se tratar de strings
  */
  while(cont	< MAX_ANO){
    fprintf(*fpt, "%d", novo->Ano[cont]);
    cont++;
  }
  cont = 0;
  while(cont < MAX_VALOR){
    fprintf(*fpt, "%d", novo->Valor[cont]);
    cont++;
  }		
  fprintf(*fpt, "%s", novo->Imagem);		
}
/*Função CompletaString:
  a função escreve, em todos os espaços do campo passado como parâmetro, o caractere ' '(espaço) e retorna ao fim de sua execução o vetor zerado. 
*/
char *CompletaString(char *campo, int tamanho){
  int cont;
  cont = 0;
  /*laço que adiciona espaços em todo o vetor
   */
  while(cont < tamanho){
    campo[cont] = ' ';
    cont++;
  }
  
  return campo;
}
/*Função LoadChaves:
  Carrega as chaves primárias e seus respectivos nrr's do arquivo de chaves para a memória e , no caso de não existir um arquivo de chaves, ele busca as chaves no banco de dados e já adiciona seu nrr. No caso de nenhum dos 2 arquivos existirem, ela simplesmente retorna o struct que foi passado
  como parâmetro, sem alocar seu vetor, mas inicializando, tanto o vetor como o número de registros
*/
Registro LoadChaves(Registro reg){
  FILE *arq;
  int k = 1;
  int i = 0;
  reg.quantidade = 0;
  reg.vetor = NULL;
  arq = fopen("chaves05.txt", "r");
  if(arq == NULL){
    arq = fopen("base05.dat", "r");
    if(arq == NULL){
      return reg;
    }
    while(!feof(arq)){
      if(i%20 == 0){  
        reg.vetor = (Chave_prim *)realloc(reg.vetor, (k++)*20*(sizeof(Chave_prim)));
      } 
      fseek(arq, (i*TAM_REG), SEEK_SET);  
      if(fgets(reg.vetor[i].Titulo, MAX_TITULO, arq) == NULL){
        fclose(arq);
        reg.quantidade = i; 
        return reg;
      }    
      reg.vetor[i].nrr = i;
      i++;
    }
  }
  while(!feof(arq)){
    if(i%20 == 0){  
      reg.vetor = (Chave_prim *)realloc(reg.vetor, (k++)*20*(sizeof(Chave_prim)));
    } 
    fgets(reg.vetor[i].Titulo, MAX_TITULO, arq);
    fscanf(arq, "%d", &(reg.vetor[i].nrr));
    i++;
  }
  reg.quantidade = i;
  fclose(arq);
  return reg;
}  
/*Função GravaChaves:
  Função que é chamada no fim da execução do programa para gravar as chaves no arquivo de chaves, bem como seu nrr.
*/
void GravaChaves(Registro reg){
  
  int i = 0;
  FILE *arq;
  
  arq = fopen("chaves05.txt", "w+");
  while(i < reg.quantidade){
    
    fprintf(arq, "%s", reg.vetor[i].Titulo);
    fprintf(arq, "%d", reg.vetor[i].nrr);			
    i++;
  }
  free(reg.vetor);
  fclose(arq);
  
  return;
  
}	

/*Função Busca:
  Recebe como parâmetro o registro que contem o vetor com as chaves primarias, a chave a ser buscada e um int denominado "caso", que serve para controle da execução determinando se quem está fazendo a busca é o usuário(caso = 0) ou o programa (caso = 1).Se a busca for feita pelo programa o programa não mexe no arquvo html e nem imprime nada na tela.No caso de busca do usuário o registro, se tiver sua pk encontrada, tem seus dados imprimidos no html, caso contrário é impressa a mensagem de "obra não encontrada"  */
int Busca(Registro reg, int caso, char *alvo){
  FILE *fpt;
  Chave_prim x;
  Chave_prim *aux;
  int y;
  
  strcpy(x.Titulo, alvo);
  aux = bsearch(&x, reg.vetor, reg.quantidade, sizeof(Chave_prim), nosso_strcmp);
  
  if (aux != NULL) {
    if(caso == 1)
      return 1;
    fpt = fopen("base05.dat", "a+");
    y = aux->nrr;
    fseek(fpt, y*TAM_REG, SEEK_SET);
    
    make_html(&fpt, 1, reg);
    fclose(fpt);
    return 0;
  }
  if (caso == 1)
    return 0;
  if (aux == NULL)
    printf("Obra não encontrada\n");
  
  return 0;
  
}

/*Função Lista:
  usa o vetor de chaves primárias, pegando o nrr de cada uma das chaves e, usando o mesmo, imprime todos os dados de cada uma das obras no html. */

void Lista(Registro reg){
  
  FILE *fpt;
  
  fpt = fopen("base05.dat", "a+");
  make_html(&fpt, reg.quantidade, reg);
  fclose(fpt);
  
  return;
  
}

/*Função nosso_strcmp:
  Função de comparacao entre strings que recebe uma string str1 e uma string str2, e compara as duas. Retorna '0' caso as duas strings sejam iguais, '1' ou '-1' caso as duas strings sejam diferentes.
  Utilizada nas funções qsort e bsearch da biblioteca padrão*/
int nosso_strcmp(const void* str1, const void* str2){
  int i=0;
  while(tolower((*(Chave_prim*)str1).Titulo[i]) == tolower((*(Chave_prim*)str2).Titulo[i])){
    if(i == MAX_TITULO-1) return 0;
    i++;
  }
  
  if(tolower((*(Chave_prim*)str1).Titulo[i]) > tolower((*(Chave_prim*)str2).Titulo[i]))
    return 1; 
  
  else if(tolower((*(Chave_prim*)str1).Titulo[i]) < tolower((*(Chave_prim*)str2).Titulo[i]))
    return -1;
  
  return -1;
}

/*Funcao make_html:
  Usa uma variável i para escrever o arquivo através da função fputc, e uma outra variável cont_reg para limitar o número de impressões no arquivo html
  Os vetores inicio_html e fim_html contém os respectivos códigos html que serão escritos no arquivo html.
*/
void make_html (FILE **fpt,int tipo, Registro reg) {
  int i = 0;
  int y;
  int cont_reg = 0;
  
  char *inicio_html;
  char *fim_html;
  FILE *htm;
  
  
  inicio_html = "<html><body><head><title>Resultado da busca no acervo 05</title></head>";
  fim_html = "</table></body></html>";
  
  htm = fopen("05.html", "w+");
  
  fputs(inicio_html, htm);
  
  while(cont_reg < tipo){
    
    /*condicional para, caso o make_html seja chamado na busca, nao realizar o fseek, pois este ja foi chamado na propria funcao busca*/
    if(tipo != 1){
      y = reg.vetor[cont_reg].nrr;
      fseek(*fpt, y*(TAM_REG), SEEK_SET);
    }
    
    /*Impressao do titulo*/
    fputs("Nome: ", htm);
    while(i < MAX_TITULO-1){
      fputc(getc(*fpt),htm);
      i++;
    }
    
    fputs("<br>", htm);
    
    /*Impressao do tipo*/
    i = 0;
    fputs("Tipo: ", htm);
    while(i < MAX_TIPO-1){
      fputc(getc(*fpt),htm);
      i++;
    }
    
    fputs("<br>", htm);
    
    /*Impressao do autor*/
    i = 0;
    fputs("Autor: ", htm);
    while(i < MAX_AUTOR-1){
      fputc(getc(*fpt),htm);
      i++;
    }
    
    fputs("<br>", htm);
    
    /*Impressao do ano*/
    i = 0;
    fputs("Ano: ", htm);
    while(i < MAX_ANO){
      fputc(getc(*fpt),htm);
      i++;
    }
    
    fputs("<br>", htm);
    
    /*Impressao do valor*/
    i = 0;
    fputs("Valor: ", htm);
    while(i < MAX_VALOR){
      fputc(getc(*fpt),htm);
      i++;
    }
    
    fputs("<br>", htm);
    
    /*Impressao da imagem*/
    i = 0;
    fputs("Imagem: ", htm);
    fputs("<br>", htm);
    fputs("<img src=img/", htm);
    while(i <= 5){
      fputc(getc(*fpt),htm);
      i++;
    }
    fputs(".", htm);
    i = 0;
    while(i <= 2){
      fputc(getc(*fpt),htm);
      i++;
    }
    i = 0;
    fputs(">", htm);
    
    fputs("<br>", htm);
    
    cont_reg++;
    
  }
  
  fputs(fim_html, htm);
  
  fclose(htm);
  return;
  
}
